package com.example.geohash.controller;

import com.example.geohash.pojo.enums.DistanceUnitEnum;
import com.example.geohash.pojo.param.GeoHashAddParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @Author douhy
 * @description geoHashDemo
 * @date 22/03/31
 */
@RestController
@RequestMapping(value = "/geoHash")
public class GeoHashController {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 添加位置信息
     *
     * @param geoHashAddParam : 请求参数
     * @return : boolean
     * @author douhy
     */
    @PostMapping(value = "/add")
    public boolean add(@RequestBody GeoHashAddParam geoHashAddParam) {
        List<RedisGeoCommands.GeoLocation<String>> geoLocations = geoHashAddParam.getGeoLocations();
        // 批量添加接口
        redisTemplate.opsForGeo()
                .add(geoHashAddParam.getRk(), geoLocations);
        return true;
    }

    /**
     * 获取位置经纬度
     *
     * @param rk      : redisKey
     * @param members : 位置集合
     * @return : List<Point>
     * @author douhy
     */
    @GetMapping(value = "/get")
    public List<Point> get(@RequestParam("rk") String rk, @RequestParam("members") String... members) {
        List<Point> points = redisTemplate.opsForGeo().position(rk, members);
        return points;
    }

    /**
     * 获取两个位置的距离
     *
     * @param rk       : redisKey
     * @param unit     : 距离单位
     * @param arrdessA : 位置A
     * @param arrdessB : 位置B
     * @return : List<Point>
     * @author douhy
     */
    @GetMapping(value = "/dist")
    public Distance dist(@RequestParam("rk") String rk, @RequestParam("unit") Integer unit, @RequestParam("arrdessA") String arrdessA, @RequestParam("arrdessB") String arrdessB) {
        Distance distance = redisTemplate.opsForGeo()
                .distance(rk, arrdessA, arrdessB, DistanceUnitEnum.getEnum(unit));
        return distance;
    }

    /**
     * 获取经纬度附近指定个数的位置信息
     *
     * @param rk        : redisKey
     * @param longitude : 经度
     * @param latitude  : 纬度
     * @param dist      : 距离
     * @param size      : 个数
     * @return : GeoResults<RedisGeoCommands.GeoLocation<String>>
     * @author douhy
     */
    @GetMapping(value = "/near")
    public GeoResults<RedisGeoCommands.GeoLocation<String>> near(@RequestParam("rk") String rk, @RequestParam("longitude") Double longitude, @RequestParam("latitude") Double latitude, @RequestParam("dist") Integer dist, @RequestParam("size") Integer size, @RequestParam(value = "memberName", required = false) String memberName) {
        System.out.println(System.currentTimeMillis());
        Point point = new Point(longitude, latitude);
        Distance distance = new Distance(dist, RedisGeoCommands.DistanceUnit.KILOMETERS);
        Circle circle = new Circle(point, distance);
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(size);
        GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo()
                .radius(rk, circle, args);
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> content = results.getContent();

//        List<String> collect = content.stream().filter(new Predicate<GeoResult<RedisGeoCommands.GeoLocation<String>>>() {
//            @Override
//            public boolean test(GeoResult<RedisGeoCommands.GeoLocation<String>> geoLocationGeoResult) {
//                return geoLocationGeoResult.getContent().getName().contains(memberName);
//            }
//        }).map(x -> {
//            return x.getContent().getName();
//        }).collect(Collectors.toList());
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> collect = content.stream().filter(new Predicate<GeoResult<RedisGeoCommands.GeoLocation<String>>>() {
            @Override
            public boolean test(GeoResult<RedisGeoCommands.GeoLocation<String>> geoLocationGeoResult) {
                return geoLocationGeoResult.getContent().getName().contains(memberName);
            }
        }).collect(Collectors.toList());


        System.out.println(collect);
        System.out.println(System.currentTimeMillis());
        return results;

    }

    /**
     * 获取指定位置 附近指定个数的位置信息
     *
     * @param rk     : redisKey
     * @param dist   : 距离
     * @param unit   : 距离单位
     * @param member : 位置名
     * @param size   : 个数
     * @return : GeoResults<RedisGeoCommands.GeoLocation<String>>
     * @author douhy
     */
    @GetMapping(value = "/nearByPlace")
    public GeoResults<RedisGeoCommands.GeoLocation<String>> nearByPlace(@RequestParam("rk") String rk, @RequestParam("dist") double dist, @RequestParam("unit") Integer unit, @RequestParam("member") String member, @RequestParam("size") Integer size) {
        Distance distance = new Distance(dist, DistanceUnitEnum.getEnum(unit));
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(size);
        GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo()
                .radius(rk, member, distance, args);
        return results;
    }

    /**
     * 获取指定位置的geoHashCode
     *
     * @param rk      : redisKey
     * @param members : 位置集合
     * @return : List<String>
     * @author douhy
     */
    @GetMapping(value = "/geoHashCode")
    public List<String> hashCode(@RequestParam("rk") String rk, @RequestParam("members") String... members) {
        List<String> results = redisTemplate.opsForGeo()
                .hash(rk, members);
        return results;
    }
}
